package com.kwan.xframe.api;


import android.os.Environment;
import android.util.Log;

import com.kwan.xframe.BaseApplication;
import com.kwan.xframe.download.DownloadProgressInterceptor;
import com.kwan.xframe.mvvm.data.source.http.HttpResult;
import com.kwan.xframe.util.ImageUtil;
import com.kwan.xframe.util.SystemUtil;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.core.Flowable;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * 接口工具类
 * Created by Mr.Kwan on 2016-3-30.
 */
public abstract class BaseAPIUtil {

	//private final String BASE_URL = BaseServerAPI.HTTP_TEST_SERVER;
	//private final String BASE_URL = ServerAPI.HTTP_SERVER;

	protected abstract String getBaseUrl();

	protected abstract String getBaseTokenUrl();

	protected abstract String getBaseUpLoadUrl();

	protected abstract String getToken();

	public static int TIME_OUT = 20000;

	private HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
		@Override
		public void log(String message) {
			Log.e("BaseAPIUtil", "loggingInterceptor:" + message);
		}
	}).setLevel(HttpLoggingInterceptor.Level.BASIC);


	public class Builder {

		private OkHttpClient.Builder builder;
		private String baseUrl;

		public Builder(String baseUrl) {
			this.baseUrl = baseUrl;

			File httpCacheDirectory = new File(BaseApplication.getInstance().getCacheDir(), "responses");
			int cacheSize = 10 * 1024 * 1024;// 10 MiB
			Cache cache = new Cache(httpCacheDirectory, cacheSize);

			builder = new OkHttpClient.Builder()
					.retryOnConnectionFailure(true)
					.connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
					.readTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
					.writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
					.cache(cache)
					.addInterceptor(loggingInterceptor);
		}

		public Builder addInterceptor(Interceptor tokenInterceptor) {
			builder.addInterceptor(tokenInterceptor);
			return this;
		}


		public Builder addNetworkInterceptors(Interceptor tokenInterceptor){
			builder.addNetworkInterceptor(tokenInterceptor);
			return this;
		}

		public Retrofit create() {
			OkHttpClient okHttpClient = builder.build();
			return new Retrofit.Builder()
					.baseUrl(baseUrl)
					.addConverterFactory(ScalarsConverterFactory.create())
					.addCallAdapterFactory(RxJava3CallAdapterFactory.createSynchronous())
					.client(okHttpClient)
					.build();
		}

	}


	public static final String TYPE_JSON = "application/json";
	public static final String TYPE_XML = "application/xml";

	public Retrofit serverAPI(final String type) {
		Interceptor interceptor = new Interceptor() {
			@Override
			public Response intercept(Chain chain) throws IOException {
				Request request = chain.request();
				try {
					if (request != null && request.body() != null) {
						MediaType mediaType = request.body().contentType();

						if (mediaType != null) {
							Field field = mediaType.getClass().getDeclaredField("mediaType");
							field.setAccessible(true);
							field.set(mediaType, type);

						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				return chain.proceed(request);
			}
		};
		return new Builder(getBaseUrl()).addInterceptor(interceptor).create();
	}

	protected Retrofit withCache() {


		Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {

			@Override
			public Response intercept(Chain chain) throws IOException {

				CacheControl.Builder cacheBuilder = new CacheControl.Builder();
				cacheBuilder.maxAge(0, TimeUnit.SECONDS);
				cacheBuilder.maxStale(365, TimeUnit.DAYS);
				CacheControl cacheControl = cacheBuilder.build();

				Request request = chain.request();

				if (!SystemUtil.checkNetWorkAvailable()) {
					request = request.newBuilder()
							.cacheControl(cacheControl)
							.build();
				}

				Response originalResponse = chain.proceed(request);

				if (SystemUtil.checkNetWorkAvailable()) {
					int maxAge = 0;// read from cache
					return originalResponse.newBuilder()
							.removeHeader("Pragma")
							.header("Cache-Control", "public ,max-age=" + maxAge)
							.build();
				} else {
					int maxStale = 60 * 60 * 24 * 28;// tolerate 4-weeks stale
					return originalResponse.newBuilder()
							.removeHeader("Pragma")
							.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
							.build();
				}
			}
		};


		return new Builder(getBaseUpLoadUrl()).
				addNetworkInterceptors(REWRITE_CACHE_CONTROL_INTERCEPTOR).
				addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR).create();
	}

	protected Retrofit upLoadAPI() {

		Interceptor tokenInterceptor = new Interceptor() {
			@Override
			public Response intercept(Chain chain) throws IOException {
				Request originalRequest = chain.request();
				Request authorised = originalRequest.newBuilder()
						.header("token", getToken())
						.build();
				return chain.proceed(authorised);
			}
		};

		return new Builder(getBaseUpLoadUrl()).addInterceptor(tokenInterceptor).create();
	}

	protected Retrofit downloadAPI(String url, DownloadProgressInterceptor.DownloadProgressListener listener) {
		DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener);
		return new Builder(url).addInterceptor(interceptor).create();
	}

	protected Retrofit withToken() {
		Interceptor interceptor = new Interceptor() {
			@Override
			public Response intercept(Chain chain) throws IOException {
				Request request = chain.request();
				try {
					if (request != null && request.body() != null) {
						MediaType mediaType = request.body().contentType();
						if (mediaType != null) {
							Field field = mediaType.getClass().getDeclaredField("mediaType");
							field.setAccessible(true);
							field.set(mediaType, "application/json");
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				return chain.proceed(request);
			}
		};

		Interceptor tokenInterceptor = new Interceptor() {
			@Override
			public Response intercept(Chain chain) throws IOException {
				Request originalRequest = chain.request();
				Request authorised = originalRequest.newBuilder()
						.header("token", getToken())
						.build();
				return chain.proceed(authorised);
			}
		};

		return new Builder(getBaseTokenUrl()).
				addInterceptor(tokenInterceptor).
				addInterceptor(interceptor).create();

	}

	public Flowable<ResponseBody> download(String url, DownloadProgressInterceptor.DownloadProgressListener listener) {
		return downloadAPI("http://192.168.0.1/", listener)
				.create(BaseServerAPI.class).download(url);
	}

	public Flowable<ResponseBody> download(String start, String url, DownloadProgressInterceptor.DownloadProgressListener listener) {
		return downloadAPI("http://192.168.0.1/", listener).create(BaseServerAPI.class).download(start, url);
	}

	public enum UPLOAD_TYPE {
		FILE, IMAGE
	}

	/**
	 * 文件上传
	 *
	 * @param file        上传文件
	 * @param fileArgName 文件的参数名
	 * @param args        参数键值对 key---参数名 ，value--参数值
	 * @param listener
	 * @return
	 */

	public Flowable<HttpResult<Object>> uploadFile(UPLOAD_TYPE TYPE, String url, File file, String fileArgName, HashMap<String, String> args,
												   CountingRequestBody.Listener listener) {

		RequestBody requestBody = null;
		if (TYPE == UPLOAD_TYPE.FILE) {
			//构建文件的 part
			requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
		} else if (TYPE == UPLOAD_TYPE.IMAGE) {
			requestBody = RequestBody.create(MediaType.parse("image/*"), file);

			//图片 还要 进行压缩
			String targetPath = Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + "_compressPic.jpg";
			//调用压缩图片的方法，返回压缩后的图片path
			final String compressImage = ImageUtil.compressImage(file.getPath(), targetPath, 30);
			final File compressedPic = new File(compressImage);

			if (compressedPic.exists()) {
				Log.d("upload", "图片压缩上传");
				file = compressedPic;
			} else {//直接上传
				//file = new File(path);
			}
		}

		CountingRequestBody prequestBody = new CountingRequestBody(requestBody, listener);
		MultipartBody.Part body = MultipartBody.Part.createFormData(fileArgName, file.getName(), prequestBody);

		//构建参数的part
		MediaType mediaType = MediaType.parse("multipart/form-data");
		Map<String, RequestBody> partMap = new TreeMap<>();

		for (Map.Entry<String, String> entry : args.entrySet()) {
			String key = entry.getKey();
			String val = entry.getValue();
			partMap.put(key, RequestBody.create(mediaType, val));
		}

		return upLoadAPI().create(BaseServerAPI.class).uploadFile(url, partMap, body);
	}


}